home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / c / vbccppcsrc.lha / vbcc / ar / archive.c < prev    next >
C/C++ Source or Header  |  1999-03-07  |  10KB  |  399 lines

  1. /* $VER: ar archive.c V0.1 (31.01.98)
  2.  *
  3.  * This file is part of ar, a portable archive maintanance
  4.  * utility for normal and BSD-style archives.
  5.  * Copyright (c) 1999  Frank Wille
  6.  *
  7.  * ar is freeware and part of the portable and retargetable ANSI C
  8.  * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
  9.  * ar may be freely redistributed as long as no modifications are
  10.  * made and nothing is charged for it. Non-commercial usage is allowed
  11.  * without any restrictions.
  12.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  13.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  14.  *
  15.  *
  16.  * v0.1  (31.01.99) phx
  17.  *       First working version, which only supports 'q' (quick append)
  18.  *       and 't' (table of contents), reads and writes normals and
  19.  *       BSD-style archives. Symbol table will not be created!
  20.  * v0.0  (29.01.99) phx
  21.  *       File created.
  22.  */
  23.  
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "ar.h"
  28. #include "archive.h"
  29. #include "errors.h"
  30.  
  31.  
  32. static const char *armag = ARMAG;
  33. static const char *arfmag = ARFMAG;
  34. static const char *symtab_name = "/ ";
  35. static const char *longnames_name = "// ";
  36.  
  37.  
  38. extern size_t filesize(FILE *,char *);
  39. extern void getfstat(struct ArObject *,char *name);
  40. extern char *filepart(char *);
  41.  
  42. static void make_long_names(struct Archive *);
  43. static struct ArObject *allocArObject(unsigned long);
  44. static bool parse_header(struct Archive *,struct ArObject *,
  45.                          struct ArHeader *);
  46.  
  47.  
  48.  
  49. struct Archive *ar_create(char *archive_name)
  50. /* create a new, empty achive */
  51. {
  52.   struct Archive *ar;
  53.  
  54.   if (ar = malloc(sizeof(struct Archive))) {
  55.     memset(ar,0,sizeof(struct Archive));
  56.     initlist(&ar->l);
  57.     ar->name = archive_name;
  58.   }
  59.   return (ar);
  60. }
  61.  
  62.  
  63. struct Archive *ar_read(char *archive_name)
  64. /* open archive and read all objects */
  65. {
  66.   struct Archive *ar = NULL;
  67.   struct ArObject *obj;
  68.   uint8 *data;
  69.   FILE *fh;
  70.   char buf[sizeof(struct ArHeader)];  /* assuming sizeof ArHeader > SARMAG */
  71.   unsigned long size;
  72.  
  73.   if (fh = fopen(archive_name,"rb")) {
  74.     /* first check for "!<arch>\n" id */  
  75.     if (fread(buf,1,SARMAG,fh) == SARMAG) {
  76.       if (!strncmp(buf,armag,SARMAG)) {
  77.         if (ar = ar_create(archive_name)) {
  78.  
  79.           /* read all archive members */
  80.           while (fread(buf,1,sizeof(struct ArHeader),fh) ==
  81.                  sizeof(struct ArHeader)) {
  82.             if (sscanf(((struct ArHeader *)buf)->ar_size,"%lu",&size) != 1) {
  83.               error(EMALFORMARHDR,ar->name,buf);
  84.               break;
  85.             }
  86.  
  87.             if (obj = allocArObject(size)) {
  88.               /* add next member to ar-list */
  89.               size = (size + 1) & ~1;   /* 16bit alignment */
  90.               if (fread(obj->data,1,size,fh) == size) {
  91.                 if (parse_header(ar,obj,(struct ArHeader *)buf)) {
  92.                   if (obj!=ar->symbol_tab && obj!=ar->long_names) {
  93.                     addtail(&ar->l,&obj->n);
  94.                     ar->entries++;
  95.                   }
  96.                 }
  97.                 else
  98.                   break;
  99.               }
  100.               else {
  101.                 error(EARMEMBREADERR,ar->name,buf);
  102.                 break;
  103.               }
  104.             }
  105.             else {
  106.               error(EOUTOFMEM);
  107.               break;
  108.             }
  109.           }
  110.         }
  111.         else
  112.           error(EOUTOFMEM);
  113.       }
  114.       else
  115.         error(EFORMATERR,archive_name);
  116.     }
  117.     else
  118.       error(EREADERR,archive_name);
  119.     fclose(fh);
  120.   }
  121.   return (ar);
  122. }
  123.  
  124.  
  125. struct Archive *ar_readorcreate(char *name,uint32 mod)
  126. {
  127.   struct Archive *ar;
  128.  
  129.   if (ar = ar_read(name))
  130.     return (ar);
  131.   if (!(mod & AR_CREATIGN))
  132.     error(ECREATARC,name);
  133.   return (ar_create(name));
  134. }
  135.  
  136.  
  137. struct ArObject *ar_newmemb(char *name)
  138. /* read a new archive member from file */
  139. {
  140.   struct ArObject *obj = NULL;
  141.   FILE *fh;
  142.   unsigned long size,xxx;
  143.  
  144.   if (fh = fopen(name,"rb")) {
  145.     size = (unsigned long)filesize(fh,name);
  146.     if (obj = allocArObject(size)) {
  147.       if (fread(obj->data,1,size,fh) == size) {
  148.         obj->name = filepart(name);
  149.         getfstat(obj,name);  /* get time, mode, uid, gid */
  150.       }
  151.       else {
  152.         obj = NULL;
  153.         error(EREADERR,name);
  154.       }
  155.     }
  156.     fclose(fh);
  157.   }
  158.   else
  159.     error(ENOFILEORDIR,name);
  160.   return (obj);
  161. }
  162.  
  163.  
  164. void ar_write(struct Archive *ar,uint32 mod)
  165. /* generate symbol table, write archive in normal or BSD format */
  166. /* @@@ FIXME currently the symbol table is not created! */
  167. {
  168.   FILE *fh;
  169.  
  170.   if (!(mod & AR_TRUNC) && !(mod & AR_BSD))
  171.     make_long_names(ar);
  172.  
  173.   if (fh = fopen(ar->name,"wb")) {
  174.     struct ArObject *obj = (struct ArObject *)ar->l.first;
  175.     struct ArObject *next;
  176.     char namebuf[20];
  177.     unsigned long offset = 0;
  178.     bool bsdname;
  179.     int len;
  180.     int maxlen = (mod & AR_BSD) ? 16 : 15;
  181.  
  182.     fprintf(fh,armag);
  183.  
  184.     /* write archive members */
  185.     while (next = (struct ArObject *)obj->n.next) {
  186.       /* write file name or reference to namebuf */
  187.       len = strlen(obj->name);
  188.       bsdname = FALSE;
  189.       if ((mod & AR_BSD) && !(mod & AR_TRUNC) && len>16) {
  190.         bsdname = TRUE;
  191.         sprintf(namebuf,"#1/%d",len);
  192.       }
  193.       else if (!(mod & AR_BSD) && !(mod & AR_TRUNC) && len>15) {
  194.         sprintf(namebuf,"/%lu",offset);
  195.         offset += len+2;
  196.       }
  197.       else if (mod & AR_BSD) {
  198.         memcpy(namebuf,obj->name,len<16?len+1:16);
  199.         namebuf[16] = '\0';
  200.       }
  201.       else
  202.         sprintf(namebuf,"%.15s/",obj->name);
  203.  
  204.       if ((mod & AR_TRUNC) && len > maxlen) {
  205.         /* warning: file name was truncated */
  206.         char buf[20];
  207.  
  208.         strcpy(buf,namebuf);
  209.         buf[maxlen] = '\0';
  210.         error(ETRUNCWARN,obj->name,buf);
  211.       }
  212.  
  213.       /* write header */
  214.       fprintf(fh,"%-16.16s%-12ld%-6u%-6u%-8o%-10lu%2s",
  215.               namebuf,obj->time,obj->uid,obj->gid,obj->mode,
  216.               bsdname?obj->size+len:obj->size,arfmag);
  217.  
  218.       if (bsdname)  /* long name first */
  219.         fwrite(obj->name,1,len,fh);
  220.  
  221.       /* write data */
  222.       fwrite(obj->data,1,obj->size,fh);
  223.  
  224.       /* alignment */
  225.       if (bsdname)
  226.         obj->size += len;
  227.       if (obj->size & 1)
  228.         fprintf(fh,"\n");
  229.  
  230.       obj = next;
  231.     }
  232.   }
  233.   else
  234.     error(ECANTWRITE);
  235. }
  236.  
  237.  
  238. static void make_long_names(struct Archive *ar)
  239. /* if archive member with a name > 15 chars are present, */
  240. /* allocate a long-names object for them */
  241. {
  242.   struct ArObject *obj = (struct ArObject *)ar->l.first;
  243.   struct ArObject *next,*lnobj;
  244.   int l;
  245.   uint32 size = 0;
  246.   char *p;
  247.  
  248.   while (next = (struct ArObject *)obj->n.next) {
  249.     if ((l = strlen(obj->name)) > 15)
  250.       size += l+2;
  251.     obj = next;
  252.   }
  253.   if (size) {
  254.     /* create long-names object and copy file names */
  255.     if (lnobj = allocArObject(size)) {
  256.       lnobj->name = "/";
  257.       p = (char *)lnobj->data;
  258.       obj = (struct ArObject *)ar->l.first;
  259.       while (next = (struct ArObject *)obj->n.next) {
  260.         if ((l = strlen(obj->name)) > 15) {
  261.           memcpy(p,obj->name,l);
  262.           p += l;
  263.           *p++ = '/';
  264.           *p++ = '\n';
  265.         }
  266.         obj = next;
  267.       }
  268.       if (size & 1)
  269.         *p = '\n';
  270.       addhead(&ar->l,&lnobj->n);
  271.       ar->entries++;
  272.     }
  273.   }
  274. }
  275.  
  276.  
  277. static struct ArObject *allocArObject(unsigned long size)
  278. {
  279.   struct ArObject *obj;
  280.   uint8 *data;
  281.  
  282.   if ((obj = malloc(sizeof(struct ArObject))) &&
  283.       (data = malloc((size+1)&~1))) {
  284.     obj->data = data;
  285.     obj->size = size;
  286.   }
  287.   else
  288.     error(EOUTOFMEM);
  289.   return (obj);
  290. }
  291.  
  292.  
  293. static bool parse_header(struct Archive *ar,struct ArObject *obj,
  294.                          struct ArHeader *hdr)
  295. /* check header and store its informations into ArObject */
  296. {
  297.   if (!strncmp(hdr->ar_fmag,arfmag,2)) {
  298.     obj->time = (time_t)strtoul(hdr->ar_time,NULL,10);
  299.     obj->uid = (uint16)strtoul(hdr->ar_uid,NULL,10);
  300.     obj->gid = (uint16)strtoul(hdr->ar_gid,NULL,10);
  301.     obj->mode = (uint16)strtoul(hdr->ar_mode,NULL,8);  /* octal */
  302.  
  303.     if (!strncmp(hdr->ar_name,symtab_name,2) ||   /* normal sym table */
  304.         !strncmp(hdr->ar_name,"__.SYMDEF ",10)) { /* BSD symbol table */
  305.       ar->symbol_tab = obj;
  306.       obj->name = (char *)symtab_name;
  307.       return (TRUE);
  308.     }
  309.  
  310.     else if (!strncmp(hdr->ar_name,longnames_name,3)) { /* long names */
  311.       ar-